#tag ClassProtected Class ZipArchive	#tag Method, Flags = &h0		Function Open(f as FolderItem, write as Boolean) As Boolean		  // Opens access to an archive with the default encoding (as used on PCs)		  //		  // - f: identifies the archive		  // - write: should specify TRUE if archive is to be created or modified, otherwise FALSE		  //		  // Returns TRUE if open was successful		  //		  // The archive is assumed to be encoded in DOSLatinUS, which is the default for Zip tools on PCs.		  // To specify a different encoding, use one of the other Open... methods		  //		  // Preconditions:		  // - Open() not has been called, or Close() has been called latest		  		  dim enc as TextEncoding		  		  #if DefaultToUnicode		    enc = me.EncodedAsUnicode		  #else		    enc = me.EncodedAsDOSLatinUS		  #endif		  		  return Open(f, write, enc)		End Function	#tag EndMethod	#tag Method, Flags = &h0		Function Entry(index_1 as Integer) As ZipEntry		  // Returns an entry from the directory of files in the archive.		  // The index starts with 1, and must be between 1 and EntryCount()		  // The entries have no particular order, and may contain directory entries		  //   with no actual file data.		  // Be aware that the Zip format allows it that several entries with the same		  //   name exist in the archive. So, if you extract all entries, be aware that you		  //   might get duplicate name conflicts.		  //		  // Preconditions:		  // - Archive is open (Open has been called, but not Close)		  		  if not me.entriesRead then		    raise new RuntimeException		  end		  		  if index_1 < 1 then		    raise new OutOfBoundsException // index must be at least 1		  end		  		  return me.d.entries_1(index_1)		End Function	#tag EndMethod	#tag Method, Flags = &h0		Function EntryCount() As Integer		  // Returns the number of entries from the directory of files in the archive.		  //		  // Preconditions:		  // - Archive is open (Open has been called, but not Close)		  		  if not me.entriesRead then		    raise new RuntimeException		  end		  		  return Ubound(me.d.entries_1)		End Function	#tag EndMethod	#tag Method, Flags = &h1		Protected Sub z_readDirectory()		  // reads the catalog at the end of the zip file		  		  dim dirlen, entryCnt, pos, len, endpos as Integer		  dim eocdr, fh, mb as MemoryBlock		  dim origname, nameWithoutSlashAtEnd, comm as String		  dim extra as ZipExtraField		  dim ze as ZipEntry		  dim zipStream as BinaryStream		  dim namesDict as Dictionary		  		  zipStream = me.d.zipStream		  		  // new 04Jul04: check the first 4 bytes of the file to make sure we have a Zip file here at all		  zipStream.Position = 0		  if zipStream.ReadLong() <> &H04034B50 then		    me.errmsg = "File does not appear to by a Zip file ('PK' header missing)"		    return		  end		  		  //		  // first, locate the "End of central dir record"		  //		  		  pos = zipStream.Length - 22		  endpos = Max(0, pos-(65536+24)) // comment can't be larger than this		  do		    if pos < endpos then		      me.errmsg = "Central Directory not found; probably a damaged Zip file"		      return		    end		    zipStream.Position = pos		    pos = pos - 1		  loop until zipStream.ReadLong() = &H06054B50		  		  // read the End of central dir record		  eocdr = NewMemoryBlock(22)		  if eocdr = nil then		    raise new OutOfMemoryException		  end		  eocdr.LittleEndian = true		  eocdr.StringValue(4,18) = zipStream.Read(18)		  		  len = eocdr.UShort(20)		  if len <> 0 then		    me.comment_ = zipStream.Read(len)		  end		  		  if eocdr.UShort(4) <> 0 or eocdr.UShort(6) <> 0 or eocdr.UShort(8) <> eocdr.UShort(10) then		    me.errmsg = "This is part of a multi-segment archive, which is not supported by the ZipArchive class"		    return		  end		  		  //		  // now read the dir records		  //		  		  me.startOfDirInArchive = eocdr.Long(16) // offset to first catalog entry, end of files in archive		  		  entryCnt = eocdr.UShort(8)		  dirlen = eocdr.Long(12)		  		  if dirlen < (entryCnt * 46) then		    me.errmsg = "Central Directory is corrupted."		    return		  end		  		  namesDict = new Dictionary		  		  if entryCnt > 0 or dirlen > 0 then		    		    zipStream.Position = me.startOfDirInArchive		    endpos = zipStream.Position + dirlen // size of entire dir		    		    // make sure that we have enough memory available to read the directory		    mb = NewMemoryBlock(4 * dirlen)		    if mb = nil then		      me.errmsg = "There is not enough memory available to read the archive directory"		      return		    end		    mb = nil		    		    //		    // read all entries from the dir, one by one		    //		    do		      fh = NewMemoryBlock(46) // size of a Central directory File header without the var length data		      fh.LittleEndian = true		      		      fh.StringValue(0,46) = zipStream.Read(46)		      if fh.Long(0) <> &H02014B50 then		        me.errmsg = "Central Directory is corrupted"		        return		      end		      if fh.UShort(6) > 20 then // version needed to extract		        // at this point I could go on and report this error only if the item shall be extracted later		        me.errmsg = "Archive was written in a newer format than what this software supports (it supports up to v2.0 archives)"		        return		      end		      len = fh.UShort(28)		      if len > 0 then		        origname = zipStream.Read(len) // get file name		      end		      len = fh.UShort(30) // extra field length		      extra = me.MakeZipExtraField(zipStream.Read(len))		      extra.Lock		      len = fh.UShort(32)		      if len > 0 then		        comm = zipStream.Read(len) // get comment		      end		      		      ze = new ZipEntry(me.d, fh, origname, extra, comm)		      me.d.entries_1.append ze		      nameWithoutSlashAtEnd = origname		      if Right (nameWithoutSlashAtEnd, 1) = "/" then		        nameWithoutSlashAtEnd = Left (nameWithoutSlashAtEnd, Len(nameWithoutSlashAtEnd)-1)		      end		      nameWithoutSlashAtEnd = EncodeBase64(nameWithoutSlashAtEnd)		      namesDict.Value(nameWithoutSlashAtEnd) = ze // base64 encoded to preserve the case		      ze = nil		      		      if entryCnt = 0 then		        // this can happen if we've got more than 65535 entries in the archive (info-zip might do this without noticing), since the "entryCnt" value is limited to 16 bit in the archive		        // let's ignore it, but disallow rewriting of the archive		        me.centralDirCorrupted = true		      end		      entryCnt = entryCnt - 1		    loop until zipStream.Position >= endpos		    		  end		  		  me.d.checkDirectory (namesDict)		  		  me.entriesRead = true		  		End Sub	#tag EndMethod	#tag Method, Flags = &h0		Function Close() As Boolean		  // Closes access to an opened archive, writing back all changes to the entries list (directory)		  // Returns FALSE if an error occured		  //		  // Note: If this call fails (i.e. FALSE is returned), the archive is probably corrupted		  // and should be deleted if it was just created. In other cases, other tools might be		  // able to recover part or all of the archive (but this software is not designed for it)		  //		  // May be called even if no archive was open (returns TRUE then)		  		  dim error as Boolean		  		  if me.d = nil or me.d.zipStream = nil then		    return true		  end		  		  if not z_writeDirectory() then		    error = true		  end		  		  me.d.zipStream.Close		  me.d.zipStream = nil		  redim me.d.entries_1(0)		  me.entriesRead = false		  me.justCreated = false		  me.marked = false		  return not error		End Function	#tag EndMethod	#tag Method, Flags = &h0		Sub ~ZipArchive()		  // destructor		  		  dim ok, deleteIfFails as Boolean		  		  if me.d <> nil and me.d.zipStream <> nil and me.justCreated then		    deleteIfFails = true		  end		  		  ok = me.Close()		  if not ok and deleteIfFails then		    me.d.theFile.Delete		  end		  		Exception exc as RuntimeException		  // ignore		End Sub	#tag EndMethod	#tag Method, Flags = &h0		Function ErrorMessage() As String		  // Returns a desciption about the latest error as an english phrase		  //		  // Function calls that could cause such an error:		  // - Open()		  // - Close()		  // - AddItemToRoot()		  // - AddItemWithRawPath()		  // - AddItemByStreams()		  // - AddFolderContents()		  // - AddFakeDuplicate()		  // - Compact()		  // - RemoveEntry()		  // - ReplaceEntry()		  // - SetComment()		  		  return me.errmsg		End Function	#tag EndMethod	#tag Method, Flags = &h0		Function Comment() As String		  // Returns the optional comment about the archive. Returns empty string if no comment available		  //		  // Preconditions:		  // - Archive is open (Open has been called, but not Close)		  		  return me.comment_		End Function	#tag EndMethod	#tag Method, Flags = &h1		Protected Function z_addItem(f as FolderItem, dos_pathname as String, encodeMB as Integer, unixAttrs as Boolean, justGetSize as Boolean) As Integer		  		  dim attr, dataLen, rsrcLen, dataLenRounded, rsrcLenRounded, idx as Integer		  dim dataFork, rsrcFork as SeqDataInputStream		  dim mbHdr as MemoryBlock		  dim useMBHdr as Boolean		  dim ef as ZipExtraField		  dim entry as ZipEntry		  		  // do we allow writing at all?		  if not justGetSize then		    if not me.writeMode then		      z_noWriteMsg		      return 0		    end		  end		  		  if f = nil then		    me.errmsg = "no file reference given"		    return 0		  end		  		  // get read access to the file (or forks)		  if not f.Directory then		    if not justGetSize then		      dataFork = new FileReader(f)		    end		    dataLen = f.Length		    #if TargetMacOS		      if encodeMB > 0 and f.ResourceForkLength > 0 then		        if not justGetSize then		          rsrcFork = new RsrcForkReader(f)		        end		        rsrcLen = f.ResourceForkLength		      end		    #endif		  end		  		  // shall we create a MacBinary header?		  #if TargetMacOS		    if encodeMB = 2 or encodeMB = 1 and (rsrcLen > 0) then		      '!!! be even smarter here? (find out what Stuffit DropZip does exactly)		      useMBHdr = true		    end		  #endif		  		  if justGetSize then		    // return the size of the data that would be read		    if useMBHdr then		      dataLenRounded = BitwiseAnd(dataLen+127,&HFFFFFF80)		      rsrcLenRounded = BitwiseAnd(rsrcLen+127,&HFFFFFF80)		      return 128 + dataLenRounded + rsrcLenRounded		    else		      return dataLen		    end		  end		  		  // create the MacBinary header		  if useMBHdr then		    mbHdr = MakeMacBinaryHeader(f, dataLen, rsrcLen, f.Name)		  end		  		  if useMBHdr then		    ef = me.MakeZipExtraField(f) // we want the full field including the name		  else		    ef = me.MakeZipExtraField(f,"") // we want the short field without the name		  end		  		  // now write the data in compressed for to the archive		  idx = z_zip(dataFork, dataLen, rsrcFork, rsrcLen, mbHdr, dos_pathname, f.ModificationDate, ef)		  		  if unixAttrs and idx > 0 then		    if me.GetUnixPermissions(f, attr) then		      entry = me.d.entries_1(idx)		      entry.SetOSMadeBy 3 // unix		      entry.SetExternalFileAttributes Bitwise.BitOr(me.d.shiftLeft16(attr),Bitwise.BitAnd(&Hffff,entry.ExternalFileAttributes))		    end		  end		  		  return idx		  		Exception exc as RuntimeException		  me.errmsg = "An unexpected error occured while storing an item"		  return -1		End Function	#tag EndMethod	#tag Method, Flags = &h0		Function Compact() As Boolean		  // Rewrites the entire archive, removing any unused		  //   (i.e. deleted) space in between.		  //		  // Preconditions:		  // - Archive is open (Open has been called, but not Close)		  // - Archive was opened for writing		  		  dim flags, i, n, entryCnt as Integer, e as ZipEntry, fh, hdr as MemoryBlock		  dim lastOffset, readpos, writepos as Integer, error as Boolean		  dim zipStream as BinaryStream		  		  if not me.writeMode then		    z_noWriteMsg		    return false		  end		  		  zipStream = me.d.zipStream		  		  // How this will work:		  // A list of all the entries is created, then this list is sorted		  //   by the offset of their compressed data in the archive.		  // Then the archive will be rewritten, skipping parts that		  //   are between these entries.		  		  entryCnt = Ubound(me.d.entries_1)		  n = entryCnt - 1		  redim me.compactEntries(n) // sorted index of entries		  redim me.compactOffset(n) // sorted offset of entries' data		  		  for i = 1 to entryCnt		    e = me.d.entries_1(i)		    hdr = e.z_Header()		    me.compactEntries(i-1) = hdr		    me.compactOffset(i-1) = hdr.Long(42)		  next		  		  z_ArrayQuickSort(0, Ubound(me.compactEntries))		  		  // now the list has been sorted and we can begin to rewrite the archive		  		  // Note: With the possible presence of fake entries, it gets complicated.		  // A fake entry does not provide the real size of the local entry. This		  // means that the local header has to be read to figure out its real size.		  // For this reason we do read every local header, even if readpos		  // equals writepos.		  		  me.marked = false		  me.d.dirty = true		  		  fh = NewMemoryBlock(30)		  fh.LittleEndian = true		  		  n = 0		  writepos = 0		  lastOffset = -1		  for i = 0 to Ubound(me.compactEntries)		    readpos = me.compactOffset(i)		    hdr = me.compactEntries(i)		    if lastOffset = readpos then		      // this comes from a repeat (fake) entry - repeat with the last written item		    else		      writepos = writepos + n		      		      // read the Local File Header		      zipStream.Position = readpos		      fh.StringValue(0,30) = zipStream.Read(30)		      // make sure the data is consistent with our Directory record		      if fh.Long(0) <> &h04034B50 then		        me.errmsg = "Invalid Local File Header signature (archive appears to be severely corrupted)"		        error = true		        exit		      end		      flags = fh.UShort(6)		      if BitwiseAnd(flags,8) <> 0 then		        // we can now remove the Data Descriptor and update the File Header fields properly		        fh.Long(14) = hdr.Long(16)		        fh.Long(18) = hdr.Long(20)		        fh.Long(22) = hdr.Long(24)		        fh.UShort(6) = BitwiseAnd(flags,65535-8)		        readpos = -1 // forces a rewrite of the header		      end		      // make sure the values match those from the directory		      if fh.UShort(8) <> hdr.UShort(10) or fh.Long(14) <> hdr.Long(16) or fh.Long(18) <> hdr.Long(20) or fh.Long(22) <> hdr.Long(24) or (flags <> hdr.UShort(8)) and not me.d.isFakeEntry(hdr,flags) then		        // oops, something does not fit. Could be an error in the archive, or in our code here.		        // let's better not mess any further with it.		        me.errmsg = "File Headers mismatch (archive appears to be severely corrupted)"		        error = true		        exit		      end		      n = 30 + fh.Long(18) + fh.UShort(26) + fh.UShort(28)		      if readpos <> writepos then		        zipStream.Position = writepos		        zipStream.Write fh.StringValue(0,30)		        z_copy readpos+30, writepos+30, n - 30		      end		      lastOffset = readpos		    end		    // finally, update the offset of this file in the directory entry		    hdr.Long(42) = writepos		  next		  		  if not error then		    me.startOfDirInArchive = writepos + n		  end		  		  // free up the space used by the class-wide arrays		  redim me.compactEntries(-1)		  redim me.compactOffset(-1)		  return not error		  		Exception exc as RuntimeException		  me.errmsg = "Compact() encountered an unexpected error"		  // free up the space used by the class-wide arrays		  redim me.compactEntries(-1)		  redim me.compactOffset(-1)		End Function	#tag EndMethod	#tag Method, Flags = &h0		Function RemoveEntry(index_1 as Integer) As Boolean		  // Removes an entry from the archive list of entries		  // Does not actually regain the used space of the stored data		  //   in the archive until ZipArchive.Compact() is called.		  //		  // Note: After the item has been removed, EntryCount()		  // will be one less, and any indexes starting behind the		  // removed entry will shift down by one.		  //		  // Preconditions:		  // - Archive is open (Open has been called, but not Close)		  // - Archive was opened for writing		  		  dim e as ZipEntry		  		  if not me.writeMode then		    z_noWriteMsg		    return false		  end		  		  if not me.entriesRead then		    raise new RuntimeException		  end		  		  if index_1 < 1 then		    raise new OutOfBoundsException		  end		  		  'e = d.entries_1(index_1)		  		  me.marked = false		  me.d.dirty = true		  		  me.d.entries_1.Remove index_1		  		  return true		End Function	#tag EndMethod	#tag Method, Flags = &h0		Sub ZipArchive()		  // default constructor		  		  z_setup		  		End Sub	#tag EndMethod	#tag Method, Flags = &h1		Protected Sub z_setup()		  		  me.d = new ZipArchiveData		  me.d.copyChunkSize = 16384		  		  me.maxIntPlus1 = Pow(2,31)		  		End Sub	#tag EndMethod	#tag Method, Flags = &h0		Function ReplaceEntry(index_1 as Integer, entry as ZipEntry) As ZipEntry		  // Replaces the entry at the index with the given one.		  // Returns the entry that was previously at this index,		  //   returns nil if an error occured		  // This function allows you to change the order of entries for		  //   sorting purposes		  //		  // Preconditions:		  // - Archive is open (Open has been called, but not Close)		  // - Archive was opened for writing		  // - entry originates from this archive, not from a different one!		  		  dim e2 as ZipEntry		  		  if not me.writeMode then		    z_noWriteMsg		    return nil		  end		  		  if not me.entriesRead then		    raise new RuntimeException		  end		  		  if index_1 < 1 then		    raise new OutOfBoundsException		  end		  		  me.marked = false		  me.d.dirty = true		  		  e2 = me.d.entries_1(index_1)		  me.d.entries_1(index_1) = entry		  		  return e2		End Function	#tag EndMethod	#tag Method, Flags = &h0		Function SetComment(comment as String) As Boolean		  // Sets the optional comment about the archive.		  // Pass an empty string to delete an existing comment		  //		  // Preconditions:		  // - Archive is open (Open has been called, but not Close)		  // - Archive was opened for writing		  		  if not me.writeMode then		    z_noWriteMsg		    return false		  end		  		  me.comment_ = comment		  me.d.dirty = true		  return true		End Function	#tag EndMethod	#tag Method, Flags = &h0		Function AddFolderContents(folder as FolderItem, prefixDOSPath as String, useMacBinary as Integer, followFileAliases as Boolean) As Boolean		  // Adds an entire folder's contents to the archive. The immediate contents of		  //   the given folder will be put relatively to the "prefixDOSPath". Pass an		  //   empty string or "/" to store them in the root of the archive directory		  //   (a leading "/" in the string will always be ignored).		  //   Be careful not to blindly pass names of FolderItems here, because they might		  //   contain "/", which is a valid name char in Mac OS 9 but not in Windows.		  //   Use ZipArchive.CleanName() on a name to change a FolderItem.Name into a		  //   valid zip file name.		  // Hidden items will not be added to the archive, neither will be Alias		  //   Files if followFileAliases=FALSE.		  // If you pass TRUE for followFileAliases, Alias files for files, but never		  //   for Folders, will be followed and their destination added to the archive.		  // useMacBinary: pass either of the MacBinary... functions from this class		  //		  // Preconditions:		  // - Archive is open (Open has been called, but not Close)		  // - Archive was opened for writing		  		  dim s as String		  		  if not me.writeMode then		    z_noWriteMsg		    return false		  end		  		  s = ReplaceAll(prefixDOSPath+"/","//","/")		  		  return z_addFolder(folder, s, followFileAliases, useMacBinary, me.d.addUnixPerm, false) = 0		End Function	#tag EndMethod	#tag Method, Flags = &h0		Sub SetProgressMonitor(monitor as ZipProgressNotifier)		  // Defines an object that implement the ZipProgressMonitor		  //   interface. Its event ZipProgress() will be called		  //   periodically while a compression or extraction is		  //   in progress.		  // The ZipProgress also has the ability to stop a		  //   compression or extraction process.		  		  me.d.monitor = monitor		End Sub	#tag EndMethod	#tag Method, Flags = &h0		Function ProgressMonitor() As ZipProgressNotifier		  return me.d.monitor		End Function	#tag EndMethod	#tag Method, Flags = &h1		Protected Function z_zip(dataIn as SeqDataInputStream, dataLenIn as Integer, rsrcIn as SeqDataInputStream, rsrcLenIn as Integer, mbHdrIn as MemoryBlock, dos_name_in as String, d as Date, extra as ZipExtraField) As Integer		  		  // This is code is taken from Mieze (http://www.dietmar-plassmann.de/mieze.html)		  // Modified Mar 2003 by TT (www.tempel.org/rb/)		  		  // Note:		  // If mbHdrIn <> nil, then a MacBinary header will be written unconditionally, so that		  // one can force to get all the HFS attributes saved even if a file has no rsrc fork		  		  dim chunkSize, dat, tim as Integer		  dim dataLenRounded, rsrcLenRounded, GepackteLaenge, writtenAmount as Integer		  dim UngepackteLaenge, dataLen, rsrcLen as Integer		  dim CRC, nxtAdj as Integer		  dim s, input, out as string		  dim total, extraLen, n, remaining, pos1, pos2, pos3, compressMode as Integer		  dim entry as ZipEntry		  dim fh as MemoryBlock		  dim extraStr, dosEncName as String		  dim monitor as ZipProgressNotifier, abort as Boolean		  dim zipStream as BinaryStream		  dim mb, mbHdr as MemoryBlock		  dim writer as ZipBinaryStreamWriter		  #if HaveEinhugurPlugin		    dim z as ZStream // 'ZStream' comes from "e-CryptIt Engine", see http://www.einhugur.com/		  #else		    dim z as ZipBinaryStreamWriter		  #endif		  		  zipStream = me.d.zipStream		  		  if Len(dos_name_in) = 0 then		    me.errmsg = "Name must not be empty"		    return -50		  end		  dosEncName = me.z_pathToEncName(dos_name_in)		  		  mbHdr = mbHdrIn		  dataLen = dataLenIn		  rsrcLen = rsrcLenIn		  if rsrcIn = nil or mbHdr = nil then		    rsrcLen = 0		  end		  if dataIn = nil then		    dataLen = 0		  end		  if mbHdr <> nil then		    if mbHdr.Long(83) <> dataLen or mbHdr.Long(87) <> rsrcLen then		      // This can't be allowed - the passed lengths must be the same that the MacBinary header uses.		      // Since this is a programming error, an exception is raised instead of a "soft" error		      raise new RuntimeException		    end		    dataLenRounded = BitwiseAnd(dataLen+127,&HFFFFFF80)		    rsrcLenRounded = BitwiseAnd(rsrcLen+127,&HFFFFFF80)		    UngepackteLaenge = 128 + dataLenRounded + rsrcLenRounded		  else		    UngepackteLaenge = dataLen		  end		  		  if d <> nil then		    // convert date/time to DOS format		    dat = d.Day + 32 * d.Month + 512 * Max(0, d.Year-1980)		    tim = d.Second \ 2 + 32 * d.Minute + 2048 * d.Hour		  end		  		  if extra <> nil then		    extraStr = extra.AsData()		    extraLen = LenB(extraStr)		    extra.Lock		  end		  		  compressMode = 0 // default: no compression		  if UngepackteLaenge > 0 then		    #if HaveEinhugurPlugin		      compressMode = 2		    #endif		  end		  		  //		  // set up a new ZipEntry		  //		  fh = NewMemoryBlock(46) // size of a Central directory File header without the var length data		  if fh = nil then		    raise new OutOfMemoryException		  end		  fh.LittleEndian = true		  fh.Long(0) = &H02014B50		  fh.Byte(4) = 20 // 14   Version made by		  fh.Byte(5) = me.d.defaultOSMadeBy // OS made by		  fh.UShort(6) = 20 // 14 00   Version needed to Extract		  if compressMode = 0 then		    fh.UShort(10) = 0 // 00 00   Compression method (Stored)		  else		    fh.UShort(10) = 8 // 08 00   Compression method (Deflate)		  end		  fh.UShort(12) = tim		  fh.UShort(14) = dat		  fh.Long(24) = UngepackteLaenge		  fh.UShort(28) = LenB(dosEncName)		  fh.UShort(30) = extraLen		  if EnableZipIt2_2_2_UnicodeSupport and dosEncName.Encoding = Encodings.UTF8 then		    fh.Long(38) = 1 // this is to tell ZipIt 2.2.2 that the file name is UTF-8 encoded		  end		  entry = new ZipEntry(me.d, fh, dosEncName, extra, "")		  		  me.d.dirty = true		  		  // position the write marker in the archive		  zipStream.Position = me.startOfDirInArchive		  writtenAmount = 0		  		  // now write the File Header, starting at the end of the last file entry		  zipStream.WriteLong(&h04034B50) // 50 4B 03 04   File Header Signature		  zipStream.Write fh.StringValue(6,10)		  pos1 = zipStream.Position		  zipStream.WriteLong(0) // CRC-32 - we'll update this later		  if compressMode = 0 then		    zipStream.WriteLong(UngepackteLaenge) // Compressed Size - same as uncompressed for "Stored" files		  else		    zipStream.WriteLong(0) // Compressed Size - we'll update this later		  end		  zipStream.WriteLong(UngepackteLaenge) // Uncompressed Size		  zipStream.WriteShort(LenB(dosEncName)) // Filename Length		  zipStream.WriteShort(extraLen) // Extra Field Length		  zipStream.Write(dosEncName) // Filename		  if extraLen > 0 then		    zipStream.Write extraStr		  end		  pos2 = zipStream.Position		  writtenAmount = 30 + LenB(dosEncName) + extraLen		  		  // -----------		  // Important note		  // -----------		  //		  // Careful: if one alters the extras field after this, the File Hdr does not get		  //   rewritten, so that the changes will only be written to the directory, leading to		  //   headers mismatch! same is true for a changed file name!		  // So, we must not provide methods that allow the change of any ZipEntry		  //   properties other than the comment (comments are stored only in the dir)		  		  		  // now write the compressed data from the file (or uncompressed if we do not have any compression plugins)		  		  if UngepackteLaenge = 0 then		    // it's a directory, no data to write here		    pos3 = pos2		  else		    monitor = me.ProgressMonitor()		    if monitor <> nil then		      // notify the start of this item		      monitor.ZipProgress entry, UngepackteLaenge, 0, abort		    end		    		    chunkSize = me.d.copyChunkSize		    		    if not abort then		      		      if compressMode = 2 then		        #if HaveEinhugurPlugin		          writer = new ZipBinaryStreamWriter(zipStream, 10)		          z = new ZStream(true, writer, nil) // 'ZStream' comes from "e-CryptIt Engine" or its "#TypeLib.rbx" plugin, see http://www.einhugur.com/		        #endif		      else		        #if HaveEinhugurPlugin		        #else		          z = new ZipBinaryStreamWriter(zipStream, 0) // we write plain, without any compression		          writer = z		        #endif		        writer.EnableCRCCalculation		      end		      		      total = 0		      		      if mbHdr<> nil then		        		        //		        // encode it all in MacBinary format		        //		        		        z.Write mbHdr.StringValue(0,128)		        		        total = 128		        nxtAdj = -128		        		        // write data fork		        if dataIn <> nil then		          if not dataIn.Open() then		            me.errmsg = "Opening the source data stream failed"		            return -38 // "file not open"		          end		          remaining = dataLen		          while remaining > 0 and not abort		            n = Min(remaining, chunkSize+nxtAdj)		            nxtAdj = 0		            s = dataIn.Read(n)		            z.Write s		            remaining = remaining - n		            total = total + LenB(s)		            if monitor <> nil and total < UngepackteLaenge then		              monitor.ZipProgress entry, UngepackteLaenge, total, abort		            end		          wend		          dataIn.Close		        end		        		        // write filler (up to 128-byte boundary)		        remaining = dataLenRounded - dataLen		        if remaining > 0 then		          mb = NewMemoryBlock(remaining)		          if mb = nil then		            raise new OutOfMemoryException		          end		          z.Write mb.StringValue(0,remaining)		          mb = nil		          total = total + remaining		        end		        		        // write rsrc fork		        if rsrcIn <> nil then		          if not rsrcIn.Open() then		            me.errmsg = "Opening the source rsrc stream failed"		            return -38 // "file not open"		          end		          remaining = rsrcLen		          while remaining > 0 and not abort		            n = Min(remaining, chunkSize+nxtAdj)		            nxtAdj = 0		            s = rsrcIn.Read(n)		            z.Write s		            remaining = remaining - n		            total = total + LenB(s)		            if monitor <> nil and total < UngepackteLaenge then		              monitor.ZipProgress entry, UngepackteLaenge, total, abort		            end		          wend		          rsrcIn.Close		        end		        		        // write another filler (up to 128-byte boundary)		        // this filler after a rsrc fork should not be necessary due to the MB specs, but it appears that		        // some decoders expect this anyways.		        remaining = rsrcLenRounded - rsrcLen		        if remaining > 0 then		          mb = NewMemoryBlock(remaining)		          if mb = nil then		            raise new OutOfMemoryException		          end		          z.Write mb.StringValue(0,remaining)		          mb = nil		          total = total + remaining		        end		        		      else		        		        //		        // write just the data fork, without MacBinary format		        //		        		        if not dataIn.Open() then		          me.errmsg = "Opening the source data stream failed"		          return -38 // "file not open"		        end		        remaining = UngepackteLaenge		        while remaining > 0 and not abort		          n = Min(remaining, chunkSize)		          z.Write dataIn.Read(n)		          remaining = remaining - n		          total = total + n		          if monitor <> nil and total < UngepackteLaenge then		            monitor.ZipProgress entry, UngepackteLaenge, total, abort		          end		        wend		        dataIn.Close		        		      end		      z.Close		    end		    		    if monitor <> nil then		      // notify the finishing of this item		      monitor.ZipProgress entry, UngepackteLaenge, UngepackteLaenge, abort		    end		    		    if abort then		      me.errmsg = "Aborted"		      return 0		    end		    		    if total <> UngepackteLaenge then		      me.errmsg = "Read error, the archived item may be corrupted"		      return -2		    end		    		    writtenAmount = writtenAmount + writer.BytesWritten		    if me.startOfDirInArchive + writtenAmount <> zipStream.Position then		      me.errmsg = "Write error, the archived item may be corrupted"		      return -2		    end		    		    if compressMode = 0 then		      CRC = writer.CRC()		      pos3 = zipStream.Position		    else		      // seek back to retrieve the CRC from the just written data		      zipStream.Position = zipStream.Position - 8		      CRC = zipStream.ReadLong()		      pos3 = zipStream.Position - 4		    end		    		    GepackteLaenge = pos3 - pos2		    		    if compressMode = 0 and GepackteLaenge <> UngepackteLaenge then		      // oops, storing failed?!		      me.errmsg = "Internal error (Store)"		      return -2		    end		    		    // now seek back and update the compressed length and CRC		    zipStream.Position = pos1		    zipStream.WriteLong CRC		    zipStream.WriteLong GepackteLaenge		    		  end		  		  // update the catalog header with CRC, compressed size and File Header offset		  fh.Long(16) = CRC		  fh.Long(20) = GepackteLaenge		  fh.Long(42) = me.startOfDirInArchive		  		  // store the new end-of-files marker (where the directory or newly added files would start)		  me.startOfDirInArchive = pos3		  		  // add the new entry to the directory and we're finished		  me.d.entries_1.append entry		  		  return Ubound(me.d.entries_1)		  		Exception err as RuntimeException		  me.errmsg = "An unexpected error occured while storing an item"		  return -2		End Function	#tag EndMethod	#tag Method, Flags = &h1		Protected Sub z_noWriteMsg()		  me.errmsg = "Archive was opened read-only"		End Sub	#tag EndMethod	#tag Method, Flags = &h1		Protected Function z_writeDirectory() As Boolean		  dim entryCnt, i, dirLen, extraLen as Integer		  dim name, extraStr, comment as String		  dim extra, hdr as MemoryBlock		  dim entry as ZipEntry, extraF as ZipExtraField		  dim zipStream as BinaryStream		  		  if not me.d.Dirty then		    return true		  end		  		  zipStream = me.d.zipStream		  		  if Ubound(me.d.entries_1) = 0 then		    // empty ZIP archives are not valid -> let's create a dummy root dir entry		    i = z_zip(nil, 0, nil, 0, nil, "/", nil, nil)		  end		  		  zipStream.Position = me.startOfDirInArchive		  		  //		  // write the directory entries		  //		  entryCnt = Ubound(me.d.entries_1)		  for i = 1 to entryCnt		    		    entry = me.d.entries_1(i)		    hdr = entry.z_Header		    name = entry.z_origEncodedName		    comment = entry.z_origEncodedComment		    extraF = entry.ExtraFieldInCentralDir()		    if extraF = nil then		      me.errmsg = entry.ErrorMessage		      return false		    end		    extraStr = extraF.AsData()		    extraLen = LenB(extraStr)		    		    if hdr.UShort(30) <> extraLen then		      // oops - something went wrong (should have been kept always in sync with extra field)		      me.errmsg = "Internal error (extra field length mismatch)"		      return false		    end		    		    hdr.UShort(28) = LenB(name)		    hdr.UShort(30) = extraLen		    hdr.UShort(32) = LenB(comment)		    		    zipStream.Write hdr.StringValue(0,46)		    zipStream.Write(name)		    if extraLen > 0 then		      zipStream.Write extraStr		    end		    zipStream.Write(comment)		    		  next		  		  dirLen = zipStream.Position - me.startOfDirInArchive		  		  zipStream.WriteLong(&h06054B50) // 50 4B 05 06   End Of Central Dir Signature		  zipStream.WriteShort(0) // 00 00   Number of this Disk		  zipStream.WriteShort(0) // 00 00   Number of the Disk with the start of the central Directory		  zipStream.WriteShort(entryCnt) // Total Number of Entries in the Central Dir on this Disk		  zipStream.WriteShort(entryCnt) // Total Number of Entries in the central Dir		  zipStream.WriteLong(dirLen) //  Size of the Central Directory		  zipStream.WriteLong(me.startOfDirInArchive) // Offset of Start of Central Directory with Respect to the starting Disk Number		  zipStream.WriteShort(LenB(me.comment_)) // Zipfile Comment Length		  zipStream.Write me.comment_		  zipStream.Length = zipStream.Position		  		  me.d.dirty = false		  		  return true		  		Exception exc as RuntimeException		  me.errmsg = "Internal error (Exception in z_writeDirectory)"		  return false		End Function	#tag EndMethod	#tag Method, Flags = &h1		Protected Function z_addFolder(folder as FolderItem, prefixDOSPath as String, followAliases as Boolean, encodeMB as Integer, unixAttrs as Boolean, justGetSize as Boolean) As Integer		  dim result, dummy, idx as Integer, name as String		  dim f, files(-1), folders(-1) as FolderItem		  dim ok, abort as Boolean		  dim total as Double		  		  if folder = nil then		    me.errmsg = "no folder reference given"		    return -1		  end		  		  // first, we collect all file and folder items into an array		  		  idx = 1		  do		    f = folder.TrueItem(idx)		    if f = nil then		      exit // end of files in this folder		    end		    if f.Alias then		      if followAliases then		        f = folder.Item(idx)		        if f.Directory then		          f = nil // ignore aliases pointing to dirs to avoid endless recursion problems		        end		      else		        f = nil // ignore all aliases		      end		    end		    if f <> nil then		      if f.Directory then		        folders.append f		      else		        files.append f		      end		    end		    idx = idx + 1		  loop		  		  // now we add all the files from this folder to the archive		  		  for idx = 0 to Ubound(files)		    f = files(idx)		    abort = false		    if me.d.monitor <> nil then		      me.d.monitor.ZipFileStarting f, abort		    end		    if abort then		      return -1		    end		    if not justGetSize then		      name = prefixDOSPath+me.d.cleanName(f.Name)		    end		    result = z_addItem(f, name, encodeMB, unixAttrs, justGetSize)		    if result < 0 or (result = 0 and not justGetSize) then		      if z_abort(f, result, me.errmsg, true) then		        abort = true		      end		    elseif justGetSize then		      total = total + result		    end		    if abort then		      return -1		    end		  next		  redim files(-1) // free the used space before the recursion happens to save some memory		  		  // finally we add all the folders inside this folder to the archive		  		  while Ubound(folders) >= 0		    f = folders(0)		    folders.Remove 0		    if not justGetSize then		      name = prefixDOSPath+me.d.cleanName(f.Name)+"/"		    end		    result = z_addFolder(f, name, followAliases, encodeMB, unixAttrs, justGetSize)		    if result < 0 then		      return result		    elseif justGetSize then		      total = total + result		    end		  wend		  		  if justGetSize then		    if total > Pow(2,31) then		      return -1 // too large, probably		    end		    return total		  else		    return 0 // success		  end		  		Exception exc as RuntimeException		  abort = z_abort(f, -1, "Unexpected error (exception) in 'z_addFolder'", false)		End Function	#tag EndMethod	#tag Method, Flags = &h1		Protected Function z_abort(f as FolderItem, code as Integer, msg as String, canCont as Boolean) As Boolean		  dim abort as Boolean		  me.errmsg = msg		  if me.d.monitor <> nil then		    me.d.monitor.ZipFileError(f, code,msg, abort)		  else		    abort = true		  end		  return not canCont or abort		End Function	#tag EndMethod	#tag Method, Flags = &h0		Sub Mark()		  // Saves the list of entries. Later, Rollback may be called		  //   to undo any addition of entries since Mark was called last.		  // It does not, however, preserve changes to existing entries.		  // This means: If you call Mark, then modify a ZipEntry, then		  //   call Rollback, the change is not undone. Only calls to AddItem		  //   and AddFolderContents will be undone.		  		  me.markDirStart = me.startOfDirInArchive		  me.markEntries = Ubound(me.d.entries_1)		  me.marked = true		End Sub	#tag EndMethod	#tag Method, Flags = &h0		Function Rollback() As Boolean		  // Undoes any added entries since the last call to Mark()		  //		  // Preconditions:		  // - Archive is open (Open has been called, but not Close)		  // - Mark has been called, but not any of these since then:		  //    - Compact		  //    - RemoveEntry		  //    - ReplaceEntry		  		  if me.marked and me.markDirStart <= me.startOfDirInArchive and me.markEntries <= Ubound(me.d.entries_1) then		    me.startOfDirInArchive = me.markDirStart		    Redim me.d.entries_1(me.markEntries)		    me.d.dirty = true		    return true		  end		  me.marked = false		End Function	#tag EndMethod	#tag Method, Flags = &h1		Protected Sub z_ArrayQuickSort(firstIdx as Integer, lastIdx as Integer)		  // used for Compact()		  dim f, q as Integer		  f = firstIdx		  while f < lastIdx		    q = z_partition(f, lastIdx)		    z_ArrayQuickSort(f, q)		    f = q + 1		  wend		End Sub	#tag EndMethod	#tag Method, Flags = &h1		Protected Function z_partition(p0 as Integer, r as Integer) As Integer		  // used for Compact()		  		  Dim p, j, mid as Integer		  mid = (p0 + r) / 2		  p = p0 - 1		  j = r + 1		  do		    do		      j = j - 1		    loop until j = mid or me.z_Compare(j, mid) < 0		    do		      p = p + 1		    loop until p = mid or me.z_Compare(p, mid) > 0		    if p < j then		      if p > mid then		        mid = p		      end		      if j < mid then		        mid = j		      end		      me.z_Swap(p, j)		      if p = mid then		        mid = j		        j = j + 1		      elseif j = mid then		        mid = p		        p = p - 1		      end		    else		      if mid = r then		        return mid-1		      else		        return mid		      end		    end		  loop		End Function	#tag EndMethod	#tag Method, Flags = &h1		Protected Function z_Compare(left as Integer, right as Integer) As Integer		  // used by Compact()		  if me.compactOffset(left) < me.compactOffset(right) then		    return -1		  else		    return 1		  end		End Function	#tag EndMethod	#tag Method, Flags = &h1		Protected Sub z_Swap(idx1 as Integer, idx2 as Integer)		  // used by Compact()		  dim tmp as Integer, mb as MemoryBlock		  mb = me.compactEntries(idx1)		  me.compactEntries(idx1) = me.compactEntries(idx2)		  me.compactEntries(idx2) = mb		  tmp = me.compactOffset(idx1)		  me.compactOffset(idx1) = me.compactOffset(idx2)		  me.compactOffset(idx2) = tmp		End Sub	#tag EndMethod	#tag Method, Flags = &h0		Function Flush() As Boolean		  // Write the directory information back to the archive		  //   so that it's in a valid state. You might want to call		  //   this after you made changes to an archive but plan		  //   to keep the archive open for longer.		  //		  // Preconditions:		  // - Archive is open (Open has been called, but not Close)		  		  if not me.writeMode then		    z_noWriteMsg		    return false		  end		  		  if not me.entriesRead then		    raise new RuntimeException		  end		  		  if not z_writeDirectory() then		    return true // we just ignore Flush calls on a read-only archive		  end		  		  if not z_writeDirectory() then		    return false		  end		  		  return true		End Function	#tag EndMethod	#tag Method, Flags = &h1		Protected Sub z_copy(fromPos as Integer, toPos as Integer, len as Integer)		  dim n, p1, p2, remain as Integer, s as String		  dim zipStream as BinaryStream		  		  if fromPos = toPos then		    return		  end		  		  zipStream = me.d.zipStream		  		  remain = len		  p1 = fromPos		  p2 = toPos		  while remain > 0		    n = Min(remain, me.d.copyChunkSize)		    zipStream.Position = p1		    s = zipStream.Read(n)		    zipStream.Position = p2		    zipStream.Write s		    p1 = p1 + n		    p2 = p2 + n		    remain = remain - n		  wend		  		End Sub	#tag EndMethod	#tag Method, Flags = &h0		Function AddItemWithRawPath(f as FolderItem, rawDOSPath as String, useMacBinary as Integer) As Integer		  // Like AddItemToRoot(), but allows you to provide the name as it shall		  //   appear in the archive directory. You can construct this name by		  //   using one of the two RawPath() functions.		  		  return z_addItem(f, rawDOSPath, useMacBinary, me.d.addUnixPerm, false)		End Function	#tag EndMethod	#tag Method, Flags = &h0		Function AddItemToRoot(f as FolderItem, useMacBinary as Integer) As Integer		  // Stores (and compresses) a file or folder in the archive. It does		  //  this by appending the file data always to the end of the archive,		  //  never replacing existing, even deleted, space in the middle of it.		  // This also appends the entry to the list of entries (directory).		  // A ZipEntry object is created that describes the stored item,		  //   f.name as the item's name. This entry is appended to the list of		  //   archive entries and its index is returned by this function.		  // If this function returns 0 or a negative number, an error had		  //   occured (ErrorMessage() will then provide a descriptive msg).		  // The path, comment and other information may then be modified		  //   by fetching the entry with Entry(), then calling the entry's		  //   Set... methods.		  // useMacBinary: pass either of the MacBinary... functions from this class		  //		  // Preconditions:		  // - Archive is open (Open has been called, but not Close)		  // - Archive was opened for writing		  // - The file's size must be below 2GB (2^31) - a ZIP limitation		  		  dim name as String		  		  if f <> nil then		    name = me.d.cleanName(f.name)		    if f.Directory then		      name = name + "/"		    end		  end		  		  return z_addItem(f, name, useMacBinary, me.d.addUnixPerm, false)		End Function	#tag EndMethod	#tag Method, Flags = &h0		Function RawPath(rootFolder as FolderItem, destItem as FolderItem) As String		  // Creates a raw path name (for AddItemWithRawPath and AddItemByStreams)		  //   from a file or folder (destItem) relative to a starting folder (rootFolder).		  //		  // Preconditions:		  // - rootFolder is a directory		  // - destItem is somewhere inside rootFolder		  		  dim i as Integer, s, names(-1) as String, f, fs(-1) as FolderItem		  		  if not rootFolder.Directory then		    // Error: 'rootFolder' is not a directory		    return ""		  end		  		  f = destItem		  do		    if z_sameFolderItem(f, rootFolder) then		      // it's a valid path		      for i = Ubound(fs) downTo 0		        names.append fs(i).name		      next		      return RawPath(names)		    elseif f = nil or z_sameFolderItem(f.Parent, f) then		      // we've reached the root - it's an invalid path		      // Error: 'destItem' is not inside 'rootFolder'		      return ""		    end		    if f <> nil then		      fs.append f		    end		    f = f.Parent		  loop		  		End Function	#tag EndMethod	#tag Method, Flags = &h0		Function RawPath(names() as String) As String		  // Creates a raw path name (for AddItemWithRawPath and AddItemByStreams)		  //   from an array of folders and a final folder or file name.		  // This is the same format that you get by calling		  //  ZipEntry.GetPath		  		  dim i as Integer, s as String		  		  for i = 0 to Ubound(names)		    s = s + "/" + me.d.cleanName(names(i))		  next		  		  return MidB(s,2) // remove the first "/" again		  		End Function	#tag EndMethod	#tag Method, Flags = &h1		Protected Function z_sameFolderItem(f1 as FolderItem, f2 as FolderItem) As Boolean		  #if TargetMacOS		    return f1.MacVRefNum = f2.MacVRefNum and f1.MacDirID = f2.MacDirID and f1.Name = f2.Name		  #else		    return f1.absolutePath = f2.absolutePath		  #endif		End Function	#tag EndMethod	#tag Method, Flags = &h0		Function IsValidName(itemName as String) As Boolean		  // Tells whether the given file or folder name can be used in		  //   the archive directory unmodified.		  // Returns FALSE if the name contains illegal chars, such as "/",		  //   returns TRUE otherwise.		  		  return itemName = me.d.cleanName(itemName)		  		End Function	#tag EndMethod	#tag Method, Flags = &h0		Function IsOpen() As Boolean		  // Returns TRUE if archive is opened		  		  return me.d.zipStream <> nil		End Function	#tag EndMethod	#tag Method, Flags = &h0		Function IsWritable() As Boolean		  // Returns TRUE if archive is open and was opened in write mode		  		  return me.d.zipStream <> nil and me.writeMode		End Function	#tag EndMethod	#tag Method, Flags = &h1		Protected Function z_makeMBHdr(dataLen as Integer, rsrcLen as Integer, macName_in as String, macType as String, macCreator as String, creationDate as Date, modificationDate as Date, f as FolderItem) As MemoryBlock		  		  dim mb as MemoryBlock, scriptCode, n as Integer		  dim macName as String, pb, spec, name as MemoryBlock		  		  macName = macName_in		  		  if macName = "" then		    raise new RuntimeException // macName must not be empty!		  end		  		  // get all the other cataloginfo about the mac file or folder:		  #if TargetMacOS		    #if TargetMachO and AvoidFSSpecCalls		      Declare Function PBGetCatalogInfoSync Lib CarbonLibName (FSRefParam as Ptr) as Integer		    #else		      Declare Function PBGetCatInfoSync Lib CarbonLibName (CInfoPBRec as Ptr) as Integer		    #endif		    if f <> nil then		      #if TargetMachO and AvoidFSSpecCalls		        ... still missing ###		      #else		        spec = me.d.FSSpecOfFolderItem (f)		        if spec <> nil then		          name = NewMemoryBlock(64)		          if name = nil then		            raise new OutOfMemoryException		          end		          name.PString(0) = spec.PString(6)		          pb = NewMemoryBlock(108)		          if pb = nil then		            raise new OutOfMemoryException		          end		          pb.Ptr(18) = name		          pb.Short(22) = spec.Short(0)		          pb.Long(48) = spec.Long(2)		          if PBGetCatInfoSync(pb) <> 0 then		            pb = nil		          else		            // success		          end		          // get the name in its classic encoding, along with the script code		          if macName = f.Name then		            macName = spec.PString(6)		            if pb <> nil then		              scriptCode = pb.Byte(94) // FXInfo.fdScript		            end		          end		        end		      #endif		    end		  #endif		  		  // convert the macName to either UTF-8 or MacRoman		  		  mb = NewMemoryBlock(128)		  if mb = nil then		    raise new OutOfMemoryException		  end		  mb.LittleEndian = false		  		  // create a MacBinary III header		  		  mb.PString(1) = LeftB(macName,63)		  mb.StringValue(65,4) = macType		  mb.StringValue(69,4) = macCreator		  if creationDate <> nil then		    mb.Long(91) = z_dblToLong(creationDate.TotalSeconds)		  end		  if modificationDate <> nil then		    mb.Long(95) = z_dblToLong(modificationDate.TotalSeconds)		  end		  		  if f <> nil then		    if f.Locked then		      mb.Byte(81) = 1		    end		    mb.Byte(106) = scriptCode		    if pb <> nil then		      mb.Byte(73) = BitwiseAnd(&HFF-&H01,pb.Byte(32+8)) // clears the "hasBeenInited" flag		      mb.Byte(101) = pb.Byte(32+9)		    elseif not f.Visible then		      mb.Byte(73) = &H40		    end		  end		  		  // for the following two fork lengths we use the value from the parms		  // instead the values from f.Length and f.ResourceForkLength, so that		  // the caller can suppress writing of the forks explicitly.		  mb.Long(83) = dataLen		  mb.Long(87) = rsrcLen		  		  mb.Long(102) = &H6D42494E // 'mBIN' - the MacBinary III identifier		  mb.Byte(122) = 130		  mb.Byte(123) = 129		  		  //		  // finally, calculate the CRC over all the data in the header		  //		  #if HaveEinhugurPlugin		    // using Einhugur's e-Crypt Engine plugin		    n = Crc16_MemoryBlock(mb, 0, 124, 0)		  #else		    // using the free but a bit outdated "TT's CRC-Plugin" from http://www.tempel.org/rb/		    n = mb.CRC_CCITT(0,124)		  #endif		  		  mb.UShort(124) = n		  		  return mb		End Function	#tag EndMethod	#tag Method, Flags = &h0		Function AddItemByStreams(dataStream as SeqDataInputStream, dataLen as Integer, rsrcStream as SeqDataInputStream, rsrcLen as Integer,  macBinaryHeader as MemoryBlock, rawDOSPath as String, extra as ZipExtraField, fileDate as Date) As Integer		  // Like AddItemWithRawPath, but allows you to provide the data and resource fork		  //   streams separately.		  // If you want the item stored with a resource fork, then it will be stored in		  //   MacBinary format, which also means you have to provide the MacBinary		  //   header explicitly. Call MakeMacBinaryHeader() and pass its value as the		  //   'macBinaryHeader' parameter to this function.		  //		  // Be careful not to pass a macBinaryHeader for folders (it's a folder if rawDOSPath		  //   end with a "/"), because that would cause confusion when unpacking them		  //   with software that is not MacBinary-aware (which is the case for most		  //   non-Mac tools).		  //		  // Preconditions:		  //   if 'macBinaryHeader' is nil, then the 'rsrcStream' parameter must be nil, too		  //   if 'rsrcStream' is not nil, then the 'macBinaryHeader' parameter must not be		  //     nil, either.		  		  dim idx as Integer		  dim dataFork, rsrcFork as SeqDataInputStream		  dim mbHdr as MemoryBlock		  		  if macBinaryHeader = nil and rsrcStream <> nil then		    raise new RuntimeException // not allowed, see preconditions above		  end		  		  if not me.writeMode then		    z_noWriteMsg		    return 0		  end		  		  idx = z_zip(dataFork, dataLen, rsrcFork, rsrcLen, mbHdr, rawDOSPath, fileDate, extra)		  		  return idx		End Function	#tag EndMethod	#tag Method, Flags = &h0		Function MakeMacBinaryHeader(f as FolderItem) As MemoryBlock		  // Use this if you plan to call 'AddItemAsStreams' and plan to		  //   add all forks of this folderItem.		  		  return z_makeMBHdr(f.Length, f.ResourceForkLength, f.Name, f.MacType, f.MacCreator, f.CreationDate, f.ModificationDate, f)		  		End Function	#tag EndMethod	#tag Method, Flags = &h0		Function MakeMacBinaryHeader(f as FolderItem, dataLen as Integer, rsrcLen as Integer, macName as String) As MemoryBlock		  // Use this if you plan to call 'AddItemAsStreams' and plan not to		  //   add all forks of this folderItem (if you do not want to add a fork,		  //   pass 0 for its length).		  //		  // Notes:		  //   'macName' must not be empty. Pass f.Name if in doubt.		  //   Mind the encoding of 'macName': if it uses any non-ASCII chars, make sure you encode them as MacRoman or		  //   any other adequate Macintosh encoding. If you pass "f.Name", this will be automatically handled for you.		  		  return z_makeMBHdr(dataLen, rsrcLen, macName, f.MacType, f.MacCreator, f.CreationDate, f.ModificationDate, f)		  		End Function	#tag EndMethod	#tag Method, Flags = &h0		Function MakeMacBinaryHeader(dataLen as Integer, rsrcLen as Integer, macName as String, macType as String, macCreator as String, creationDate as Date, modificationDate as Date) As MemoryBlock		  // Use this if you plan to call 'AddItemAsStreams' and are running on		  //   Windows or have other reasons to specify the data explicitly instead		  //   implicitly by a FolderItem.		  //		  // Notes:		  //   'macName' must not be empty. Pass 'f.Name' if in doubt.		  //   'modificationDate' and 'creationDate' may be nil		  //   Mind the encoding of 'macName': if it uses any non-ASCII chars, make sure you encode them as MacRoman or		  //   any other adequate Macintosh encoding		  		  return z_makeMBHdr(dataLen, rsrcLen, macName, macType, macCreator, creationDate, modificationDate, nil)		End Function	#tag EndMethod	#tag Method, Flags = &h1		Protected Function z_dblToLong(d as Double) As Integer		  dim tmp as Integer		  if d >= me.maxIntPlus1 then		    tmp = d - me.maxIntPlus1 - me.maxIntPlus1		    return tmp		  else		    return d		  end		End Function	#tag EndMethod	#tag Method, Flags = &h0		Function MakeZipExtraField(f as FolderItem) As ZipExtraField		  // Constructor. Creates an entry to preserve Mac or Windows specific file or folder information		  return MakeZipExtraField(f, f.Name)		End Function	#tag EndMethod	#tag Method, Flags = &h0		Function MakeZipExtraField(f as FolderItem, macName as String) As ZipExtraField		  // Constructor. Creates an entry to preserve Mac or Windows specific file or folder information		  // "macName" is the name the file shall have on a Mac when it's unpacked from the archive again.		  //   this is relevant if the name contains special chars that are not allowed in the archive directory		  //   due to DOS naming conventions, and so this Mac name will be stored in a separate place.		  // If you pass an empty string, the shorter ZipIt-specific field (code &H2605) will be used,		  //   but you must not allow this if you're also writing a MacBinary header, because ZipIt expects		  //   to find the longer field (code &H2705) in oder to detect a MacBinary header automatically!		  		  #if TargetMacOS		    if macName <> "" or not f.Directory then // if neither name or type&creator are available, we don't need to do this		      return MakeZipExtraField(f.MacType, f.MacCreator, macName)		    end		  #endif		  		End Function	#tag EndMethod	#tag Method, Flags = &h0		Function MakeZipExtraField(macType as String, macCreator as String, macName as String) As ZipExtraField		  // Constructor. Creates an entry to preserve Mac specific file information.		  // "macType" and "macCreator" are the codes that Mac files, but not folders, have.		  // "macName" is the name the file shall have on a Mac when it's unpacked from the archive again.		  //   this is relevant if the name contains special chars that are not allowed in the archive directory		  //   due to DOS naming conventions, and so this Mac name will be stored in a separate place.		  // Leave "macName" empty to not have it explicitly stored (saves a little space), but not when you're		  //   also using MacBinary (or ZipIt won't detect the MB header when unpacking your archive)!		  		  dim n as Integer, newName as String, data as MemoryBlock, te as TextEncoding		  		  // We must encode the name into a classic Mac encoding here, but the macName is probably encoded in Unicode		  if macName <> "" then		    te = GuessJapaneseEncoding(macName) '### modernize this? (look for other places of this use, too!)		    if te <> nil and te.base = &H100 then		      newName = me.d.encodeForZip(macName)		    else		      // if it's not unicode, we take the given name without change. I (TT) think that's the best solution. Feel free to change it, though.		      newName = macName		    end		  end		  		  // preserve Type & Creator the way ZipIt does it		  if newName <> "" then		    // the long form, including the explicit Mac file name		    n = 1 + LenB(newName)		  else		    // the short form, without the explicit Mac file name		    n = 0		  end		  data = NewMemoryBlock(16 + n)		  if data = nil then		    raise new OutOfMemoryException		  end		  data.LittleEndian = true		  if n <> 0 then		    data.UShort(0) = &H2605		  else		    data.UShort(0) = &H2705		  end		  data.UShort(2) = data.Size-4		  data.LittleEndian = false		  data.Long(4) = &H5A504954 // "ZPIT"		  if n <> 0 then		    data.PString(8) = newName		  end		  data.StringValue(8+n,4) = macType		  data.StringValue(12+n,4) = macCreator		  		  return MakeZipExtraField(data.StringValue(0,data.Size))		  		End Function	#tag EndMethod	#tag Method, Flags = &h0		Function MakeZipExtraField(fieldData as String) As ZipExtraField		  // Constructor		  // "fieldData" is the entire set of bytes that'll be stored in the extras field		  		  return new ZipExtraField(me.d, fieldData)		End Function	#tag EndMethod	#tag Method, Flags = &h0		Function EncodedAsWinLatin1() As TextEncoding		  // Use this to open archives created by or for Aladdin's Stuffit (http://www.aladdinsys.com/)		  // Pass the result of this function to the 3rd parameter of Open()		  		  return GetTextEncoding(&H500) // WinLatin1		End Function	#tag EndMethod	#tag Method, Flags = &h0		Function EncodedAsUnicode() As TextEncoding		  // Use this to open archives created by or for ZipIt v2.2.2 or later (http://www.maczipit.com/)		  // Use this also if you're planning to read/write the archive only with this software, because		  // the use of Unicode is causing the least amout of problems with all the possible languages (scripts)		  // Pass the result of this function to the 3rd parameter of Open()		  		  return Encodings.UTF8		End Function	#tag EndMethod	#tag Method, Flags = &h0		Function EncodedAsMacDefault() As TextEncoding		  // Use this to open archives created by or for ZipIt up to v2.2 (http://www.maczipit.com/)		  // Note: This call does not work on Windows, only on Mac OS, so avoid this		  //   encoding if you create archives for interchange with Windows.		  // Pass the result of this function to the 3rd parameter of Open()		  		  dim enc as TextEncoding		  		  enc = GetFontTextEncoding("System")		  if enc = nil then		    enc = Encodings.MacRoman		  end if		  		  return enc		End Function	#tag EndMethod	#tag Method, Flags = &h0		Function EncodedAsDOSLatinUS() As TextEncoding		  // Use this to open archives created or meant for most Zip tools (on PCs, Unix, Linux, etc.)		  // Pass the result of this function to the 3rd parameter of Open()		  		  return GetTextEncoding(&H400) // code page 437		End Function	#tag EndMethod	#tag Method, Flags = &h0		Function Open(f as FolderItem, write as Boolean, encoding as TextEncoding) As Boolean		  // Opens access to an archive with a given Text Encoding		  //		  // - f: identifies the archive		  // - write: should specify TRUE if archive is to be created or modified, otherwise FALSE		  // - encoding: the encoding the archive is using or shall use. Pass nil to ignore any encodings		  //    (careful: passing nil can lead to weird results - test with foreign chars on all the		  //    platforms you want to use this software!). Or pass one of the EncodedAs... functions		  //		  // Returns TRUE if open was successful		  //		  // Preconditions:		  // - Open() not has been called, or Close() has been called latest		  		  dim ok as Boolean		  		  me.errmsg = ""		  		  if me.entriesRead then		    raise new RuntimeException		  end		  		  if f = nil then		    me.errmsg = "No file specified"		    return false		  end		  		  me.d.theFile = f		  me.d.setArchiveEncoding encoding		  		  if write and not f.exists then		    me.d.zipStream = f.CreateBinaryFile("application/zip")		    if me.d.zipStream = nil then		      me.errmsg = "Creating the archive file failed"		    else		      me.d.zipStream.LittleEndian = true		      me.entriesRead = true		      me.justCreated = true		      ok = true		    end		  else		    me.d.zipStream = f.OpenAsBinaryFile(write)		    if me.d.zipStream = nil then		      me.errmsg = "Opening the archive file failed"		    else		      me.d.zipStream.LittleEndian = true		      me.z_readDirectory() // sets "errmsg"		      ok = me.entriesRead		      if not ok then		        me.d.zipStream.Close		        me.d.zipStream = nil		      end		    end		  end		  		  me.writeMode = write and ok and not me.centralDirCorrupted		  if me.writeMode then		    me.d.Dirty = true		  end		  		  return ok		  		Exception exc as RuntimeException		  me.errmsg = "Unexpected error (exception)"		  return false		End Function	#tag EndMethod	#tag Method, Flags = &h0		Function MacBinaryNever() As Integer		  // Means to never save files MacBinary encoded		  		  return 0		End Function	#tag EndMethod	#tag Method, Flags = &h0		Function MacBinarySmart() As Integer		  // Means to save files MacBinary encoded only if the item has a resource fork.		  // But only on Mac OS -- on Windows, MacBinary will not be used even with this option.		  //		  // To save Resource Forks when running on Windows, you have to use AddItemByStreams()		  		  return 1		End Function	#tag EndMethod	#tag Method, Flags = &h0		Function MacBinaryAlways() As Integer		  // Means to save all files MacBinary encoded.		  // But only on Mac OS -- on Windows, MacBinary will not be used even with this option.		  //		  // To save Resource Forks when running on Windows, you have to use AddItemByStreams()		  		  return 2		End Function	#tag EndMethod	#tag Method, Flags = &h0		Function CalcItemSize(f as FolderItem, useMacBinary as Integer) As Integer		  // returns the size that the file would report via the ZipProgressNotifier		  // when it would be stored in the archive using AddItem...()		  		  return z_addItem(f, "", useMacBinary, false, true)		End Function	#tag EndMethod	#tag Method, Flags = &h0		Function CalcFolderSize(folder as FolderItem, followFileAliases as Boolean, useMacBinary as Integer) As Integer		  return z_addFolder(folder, "", followFileAliases, useMacBinary, false, true)		End Function	#tag EndMethod	#tag Method, Flags = &h0		Function AddFakeDuplicate(entry as ZipEntry, newRawDOSPath as String, newDate as Date, newExtraField as ZipExtraField) As Integer		  // Caution: This adds a new entry to the central directory, referring to an existing		  // local entry. This added entry's file name, date and Extra Field may differ from		  // the local header, which means it may not be seen as valid by other Zip tools.		  // Because of this, use this function with caution, preferrably only if you plan		  // to unpack the archive with this Zip package, which knows about this special case		  // and does not consider it an error.		  //		  // Note that some Zip unarchiving tools cannot handle fake entries. This includes the Unzip		  // tool the Mac OS X Finder uses to uncompress a Zip archive.		  //		  // A fake entry is marked this way: There is a bit in the header flags that indicates whether the		  // length and CRC information is present right in the header or instead behind the compressed data.		  // This bit (#3) will set in the central directory header's flags, while it will be clear in the local		  // header. This combination is not occuring in normal archives, and using this bit for this purpose		  // ensures that the fake entries can usually still be unpacked in some way using standard zip tools.		  //		  // Parameters:		  //   newRawDOSPath: the new file name and path (stored only in the central dir, not the local header);		  //     note that this name uses "/" as directory separator (see the CleanName function)		  //   newDate: if not nil, this date will be recorded as the item's date in the central dir only,		  //     otherwise the old date will be used.		  //   newExtraField: if not nil, this new extra field will be stored in the central dir,		  //     otherwise the old extra field will be used.		  // Returns the index to the added entry (which is >= 1), or 0 or a negative value in case of an error.		  		  dim newEntry as ZipEntry, fh as MemoryBlock, dosEncName as String, ef as ZipExtraField		  		  // do we allow writing at all?		  if not me.writeMode then		    z_noWriteMsg		    return 0		  end		  		  if entry = nil then		    me.errmsg = "no entry reference given"		    return 0		  end		  		  dosEncName = me.d.encodeForZip(newRawDOSPath)		  		  if newExtraField <> nil then		    ef = newExtraField		  else		    ef = entry.ExtraField // we handle EF's as immutable, so we do not need to clone it here		  end		  		  fh = z_cloneMB(entry.z_Header)		  fh.UShort(28) = LenB(dosEncName)		  if d <> nil then		    // update item's date/time		    fh.UShort(12) = newDate.Second \ 2 + 32 * newDate.Minute + 2048 * newDate.Hour		    fh.UShort(14) = newDate.Day + 32 * newDate.Month + 512 * Max(0, newDate.Year-1980)		  end		  		  // let's mark this fake entry so that we can later identify it		  fh.UShort(8) = BitwiseOr(fh.UShort(8), 8) // set bit 3 in the Flags field of the central dir header only		  		  newEntry = new ZipEntry(me.d, fh, dosEncName, ef, entry.Comment)		  		  // add the new entry to the directory and we're finished		  me.d.entries_1.append newEntry		  return Ubound(me.d.entries_1)		  		Exception exc as RuntimeException		  me.errmsg = "An unexpected error occured while adding a duplicate item"		  return -1		End Function	#tag EndMethod	#tag Method, Flags = &h1		Protected Function z_cloneMB(mb as MemoryBlock) As MemoryBlock		  dim mb2 as MemoryBlock		  if mb.Size > 0 then		    mb2 = new MemoryBlock(mb.Size)		    mb2.StringValue(0, mb.Size) = mb.StringValue(0, mb.Size)		    mb2.LittleEndian = mb.LittleEndian		    return mb2		  end		End Function	#tag EndMethod	#tag Method, Flags = &h0		Function CleanName(s as String) As String		  // If you want to pass an existing file name to the "DOSPath" parameter of 		  // one of the Add... functions, you should clean this name with this function first!		  		  // "/" and "\" are illegal chars in DOS file names and Zip archives, so we need to replace them with legal chars:		  dim s2 as String, i as Integer		  i = s.Encoding.Code		  s2 = me.d.cleanName(s)		  if i <> s2.Encoding.Code then		    raise new RuntimeException // Appears to be a RB bug - use the "TT's String-Plugin" if you're using an older RB version and enable the next line instead of this:		    'TTsStringSetEncoding s2, i //this is necessary in RB 4.5 because ReplaceAll destroys the encoding info		  end		  return s2		End Function	#tag EndMethod	#tag Method, Flags = &h0		Sub SetDefaultOSMadeBy(code as Integer)		  // See the "PKZIP format.txt" or any "appnote.txt" on the web for the codes		  //		  // This code well be used for all newly added ZipEntries		  // Default is 0.		  //		  // Call DefaultOSMadeBy() to get the current default value		  		  me.d.defaultOSMadeBy = code		End Sub	#tag EndMethod	#tag Method, Flags = &h0		Function DefaultOSMadeBy() As Integer		  return me.d.defaultOSMadeBy		End Function	#tag EndMethod	#tag Method, Flags = &h0		Function GetUnixPermissions(f as FolderItem, ByRef perm as Integer) As Boolean		  //		  // Retrieves the Unix permissions of the given file.		  // Works only in Mac OS with HFS+ or UFS volumes, but not on Windows		  //		  		  #if TargetMacOS		    		    dim fsref as MemoryBlock, res, v as Integer		    		    fsref = me.d.makeFSRef(f)		    if fsref <> nil then		      res = me.d.getUnixPermissionsFromFile(fsref, v)		      if res = 0 then		        perm = v		        return true		      end		    end		    		  #endif		End Function	#tag EndMethod	#tag Method, Flags = &h0		Sub PreserveUnixPermissions(enabled as Boolean)		  me.d.addUnixPerm = enabled		End Sub	#tag EndMethod	#tag Method, Flags = &h0		Function PreservingUnixPermissions() As Boolean		  return me.d.addUnixPerm		End Function	#tag EndMethod	#tag Method, Flags = &h0		Function Version() As Double		  return 1.3		End Function	#tag EndMethod	#tag Method, Flags = &h0		Function EntryIdxByRawPath(path as String, startIdx as Integer = 1) As Integer		  // Looks up an entry by name, starting either at the start of the list of entries or at the given index (which has to be between 1 and EntryCount+1)		  //		  // Preconditions:		  // - Archive is open (Open has been called, but not Close)		  		  if not me.entriesRead then		    raise new RuntimeException		  end		  		  if startIdx < 1 or startIdx > EntryCount+1 then		    raise new OutOfBoundsException // index must be at least 1		  end		  		  return me.d.lookup (me.z_pathToEncName(path), startIdx)		End Function	#tag EndMethod	#tag Method, Flags = &h1		Protected Function z_pathToEncName(dos_path as String) As String		  dim dos_name as String		  dos_name = dos_path		  if Len(dos_name) = 0 then		    dos_name = "/"		  elseif dos_name <> "/" and LeftB(dos_name,1) = "/" then		    dos_name = MidB(dos_name, 2)		  end		  return me.d.encodeForZip(dos_name)		End Function	#tag EndMethod	#tag Method, Flags = &h0		Function UsesAppleDittoFormat() As Boolean		  // Returns true if archive uses the Mac OS 10.4's (Tiger) format		  // where resource forks and other HFS infos are stored in "._" entries		  // (usually inside a "__MACOSX" folder)		  return me.d.dittoFormat		End Function	#tag EndMethod	#tag Method, Flags = &h0		Function AllEntriesAsRawPaths() As String()		  // Returns an array of all current entries in the directory. Useful for debugging.		  //		  // To quickly view the list, use either:		  //   MsgBox Join(zar.AllEntriesAsRawPaths(), EndOfLine)		  // or:		  //   System.DebugLog Join(zar.AllEntriesAsRawPaths(), EndOfLine)		  		  dim list() as String		  dim idx, lastIdx as Integer		  lastIdx = Ubound(me.d.entries_1)		  for idx = 1 to lastIdx		    list.Append me.d.entries_1(idx).RawPath()		  next		  return list		End Function	#tag EndMethod	#tag Note, Name = About				This is a collection of Classes to extract and create ZIP archives		(PKZIP and Info-ZIP formats).				It was written very throughly, and tries to deal with all eventualities,		such as detection of corrupted archives, and making sure enough		memory is available for opening the archive and for adding and		extracting items.				It implements only a subset of the entire ZIP archive		definition, though. Here are the known restrictions:				* Can't do encryption (neither decryption).		* Supports only "stored" and "deflate" compression methods.		* Can't read all possible ZIP archives since some of them use		   different compression methods, but if you're using any		   Zip creating tool, you usually have control over which		   methods should be used. And "deflate" is usually the most		   effective, anyways.		* No support for multi-segment archives.		* There is no provision for loss of file name information under		   older Mac OS versions (before 9): If an archive items has a		   name longer than 31 chars and if it is extracted using		   ZipEntry.MakeDestination(), the name may get cut off at		   the end without preserving an extension. Under Mac OS 9		   and later, as well as MS Windows, this should not be a problem,		   though.		* Can't deal well with corrupted archives. Theoretically, if		   parts of an archive are corrupted, redundant information in		   the archive should allow to retrieve the non-damaged data.		   But that requires extended functionality that these classes		   do not contain. At least, however, this software should be		   able to detect such damaged archives so that the user can use		   other options (more capable tools) to deal with this exceptional		   case.		* It can create "fake" entries, i.e. extra entries that refer to any		   file in the archive, allowing to have several entries even refer		   to the same file. However, this feature is not supported by		   some other Zip tools, including the one used by the Mac Finder.		   So, it's best to use this feature only if you are using these		   classes to read from the archive again.		* Supports preserving of Resource Forks using the MacBinary		   format. This format, however, is not supported by Apple's		   Unzip tools, sadly. (It should be supported, as it has been a		   well documented format for many years, but what can we do).		* Supports reading of Resource Forks written by Apple's Zip		   tool (which uses the "__MACOSX" folders for such data), but		   cannot create such folders itself (yet).				The only thing to be sure about is that files created by this		class can be read by any modern ZIP tool, such as ZipIt (for		Mac OS), WinZIP (for Windows), Stuffit Expander (Mac		and Windows) and, of course, by this class collection.				A nice feature is that you can not only add items to an existing		archive, but even remove them and then compact the archive		to gain the space back.				For more information about the ZIP archive format, search		on www.google.com for "ZIP format appnote". The "appnote.txt"		describes the format.				This code has been developed using RB 2007r1		It has been tested on Mac OS X 10.4.8 on PPC and Intel Macs, and on Windows XP SP2			#tag EndNote	#tag Note, Name = Plugins you will need				You need the following Plugins:				  * e-CryptIt Engine (from <http://www.einhugur.com/>)		  * #TypeLib (comes with the e-CryptIt plugin)			#tag EndNote	#tag Note, Name = Copyrights, Acknowledgements				e-CryptIt Engine copyright Björn Eiríksson (www.einhugur.com)				e-CryptIt Engine uses zlib code, copyright © 1995-2002		Jean-Loup Gailly and Mark Adler.				Original zip format REALbasic code was written by Carsten		Friehe for the Mieze program (http://carsten-friehe.de/).				RB code improved and reorganized by Thomas Tempelmann		(http://www.tempel.org/rb/) for public release.				Some of the design and error messages was influenced by Java 1.1's		ZipFile and related classes.				This RB code, written by Carsten Friehe and Thomas Tempelmann,		is given to the Public Domain, which means you can do whatever		you want with it. It is, however appreciated if you would "tip"		me by sending me a few dollars for my work (it took me a several		weeks to develop this software for people like you - I myself		could have done with much less for my own needs, but I wanted		to provide this as a clean and complete solution so that others		won't have to deal with this not-trivial task).				My thanks go to Leonard Rosenthol (author of Stuffit Zip support		and maintainer of MacBinary format) and Tom Brown (author		of ZipIt) for providing helpful information.				Please visit the following web address to find out how to tip me:				    http://tip.tempel.org/				Enjoy!				14 March 2003		Thomas Tempelmann			#tag EndNote	#tag Property, Flags = &h1		Protected entriesRead As Boolean	#tag EndProperty	#tag Property, Flags = &h1		Protected errmsg As String	#tag EndProperty	#tag Property, Flags = &h1		Protected comment_ As String	#tag EndProperty	#tag Property, Flags = &h1		Protected maxIntPlus1 As Double	#tag EndProperty	#tag Property, Flags = &h1		Protected writeMode As Boolean	#tag EndProperty	#tag Property, Flags = &h1		Protected startOfDirInArchive As Integer	#tag EndProperty	#tag Property, Flags = &h1		Protected justCreated As Boolean	#tag EndProperty	#tag Property, Flags = &h1		Protected marked As Boolean	#tag EndProperty	#tag Property, Flags = &h1		Protected markEntries As Integer	#tag EndProperty	#tag Property, Flags = &h1		Protected markDirStart As Integer	#tag EndProperty	#tag Property, Flags = &h1		Protected compactEntries(-1) As MemoryBlock	#tag EndProperty	#tag Property, Flags = &h1		Protected compactOffset(-1) As Integer	#tag EndProperty	#tag Property, Flags = &h1		Protected d As ZipArchiveData	#tag EndProperty	#tag Property, Flags = &h1		Protected centralDirCorrupted As Boolean	#tag EndProperty	#tag ViewBehavior		#tag ViewProperty			Visible=true			Group="ID"			InheritedFrom="Object"		#tag EndViewProperty		#tag ViewProperty			Visible=true			Group="ID"			InitialValue="-2147483648"			InheritedFrom="Object"		#tag EndViewProperty		#tag ViewProperty			Visible=true			Group="ID"			InheritedFrom="Object"		#tag EndViewProperty		#tag ViewProperty			Visible=true			Group="Position"			InitialValue="0"			InheritedFrom="Object"		#tag EndViewProperty		#tag ViewProperty			Visible=true			Group="Position"			InitialValue="0"			InheritedFrom="Object"		#tag EndViewProperty	#tag EndViewBehaviorEnd Class#tag EndClass